﻿namespace Pathfinder.Base.UI
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Media;
    using Bridge.UI;
    using Bridge.UI.Utilities;
    using Pathfinder.Base.Constructs;
    using System.Windows.Data;

    /// <summary>
    /// Interaction logic for EditPathfinderCharacter.xaml
    /// </summary>
    public partial class EditPathfinderCharacter : UserControl
    {
        public EditPathfinderCharacter(PathfinderCharacterView characterView)
        {
            InitializeComponent();

            mCharacter = characterView.PathfinderCharacter;
            mPathfinderCharacterView = characterView;

            UpdateKeys();
            UpdateValues();
            mIsRefreshing = false;
        }

        #region Private Fields

        private PathfinderCharacter mCharacter;
        private Dictionary<SubType, CheckBox> mSubtypes = new Dictionary<SubType, CheckBox>();
        private Dictionary<SightType, StackPanel> mSight = new Dictionary<SightType, StackPanel>();
        private bool mIsRefreshing = true;
        private PathfinderCharacterView mPathfinderCharacterView;

        #endregion

        #region Private Methods

        private void BindDefense()
        {
            Binding acNumberBinding = new Binding("FullAC") { Source = mCharacter };
            Binding ffNumberBinding = new Binding("FlatFootedAC") { Source = mCharacter };
            Binding thNumberBinding = new Binding("TouchAC") { Source = mCharacter };
            Binding armorClassListBinding = new Binding("ArmorClassViews") { Source = mPathfinderCharacterView };
            Binding drListbinding = new Binding("DRViews") { Source = mPathfinderCharacterView };
            Binding erListBinding = new Binding("ERViews") { Source = mPathfinderCharacterView };
            textBlockACNumber.SetBinding(TextBlock.TextProperty, acNumberBinding);
            textBlockFFNumber.SetBinding(TextBlock.TextProperty, ffNumberBinding);
            textBlockTouchNumber.SetBinding(TextBlock.TextProperty, thNumberBinding);
            listBoxArmorClass.SetBinding(ListBox.ItemsSourceProperty, armorClassListBinding);
            listBoxDamageReduction.SetBinding(ListBox.ItemsSourceProperty, drListbinding);
            listBoxEnergyReduction.SetBinding(ListBox.ItemsSourceProperty, erListBinding);
        }

        private void BindMain()
        {
            Binding sensesListBinding = new Binding("SightViews") { Source = mPathfinderCharacterView };
            Binding nameBinding = new Binding("Name") { Source = mCharacter };
            Binding crBinding = new Binding("CR") { Source = mCharacter };
            Binding alignmentBinding = new Binding("Alignment") { Source = mPathfinderCharacterView };
            Binding alignmentListBinding = new Binding("Alignments") { Source = mPathfinderCharacterView };
            listBoxSenses.SetBinding(ListBox.ItemsSourceProperty, sensesListBinding);
            textBoxName.SetBinding(TextBox.TextProperty, nameBinding);
            textBoxCR.SetBinding(TextBox.TextProperty, crBinding);
            comboBoxAlignment.SetBinding(ComboBox.ItemsSourceProperty, alignmentListBinding);
            comboBoxAlignment.SetBinding(ComboBox.SelectedItemProperty, alignmentBinding);
        }

        private void BindOffense()
        {
            Binding speedsListBinding = new Binding("SpeedViews") { Source = mPathfinderCharacterView };
            listBoxSpeeds.SetBinding(ListBox.ItemsSourceProperty, speedsListBinding);
        }

        private void UpdateKeys()
        {
            UpdateMainSectionKeys();
            UpdateDefenseSectionKeys();
            BindDefense();
            BindMain();
            BindOffense();
            UpdateSkillsContextMenu();
        }

        private void UpdateValues()
        {
            UpdateMainSectionValues();
            UpdateDefenseSectionValues();
            UpdateOffenseSectionValues();
            UpdateStatisticsSectionValues();
        }

        private void UpdateDefenseSectionKeys()
        {
            for (int i = 0; i < 40; i++)
            {
                comboBox6HitDice.Items.Add(i);
                comboBox8HitDice.Items.Add(i);
                comboBox10HitDice.Items.Add(i);
                comboBox12HitDice.Items.Add(i);
            }
        }

        private void UpdateSkillsContextMenu()
        {
            contextMenuButtonAddSkills.Items.Clear();
            string addSkills = "Craft,Knowledge,Perform,Profession";
            foreach (string skill in addSkills.Split(','))
            {
                MenuItem menuItemSkill = new MenuItem() { Header = skill };
                foreach (string subskill in Skill.GetAllSubskillNames(skill))
                {
                    MenuItem menuItemSubskill = new MenuItem() { Header = subskill, Tag = skill + "," + subskill };
                    menuItemSubskill.Click += new RoutedEventHandler(menuItemSubskill_Click);
                    menuItemSkill.Items.Add(menuItemSubskill);
                }
                contextMenuButtonAddSkills.Items.Add(menuItemSkill);
            }

        }



        private void UpdateMainSectionKeys()
        {
            comboBoxAlignment.ItemsSource = CreateKeys<Alignment>();
            comboBoxType.ItemsSource = CreateKeys<CreatureType>();
            comboBoxSize.ItemsSource = CreateKeys<SizeType>();

            StackPanel mainSubtypeStackPanel = new StackPanel();
            StackPanel rowStackPanel = new StackPanel() { Orientation = Orientation.Horizontal };
            mainSubtypeStackPanel.Children.Add(rowStackPanel);
            int number = 0;
            foreach (SubType subtype in Enum.GetValues(typeof(SubType)))
            {
                number++;
                if (number > 3)
                {
                    number = 1;
                    rowStackPanel = new StackPanel() { Orientation = Orientation.Horizontal };
                    mainSubtypeStackPanel.Children.Add(rowStackPanel);
                }
                CheckBox checkBox = new CheckBox()
                {
                    Width = 75,
                    Content = GetDisplayName(subtype),
                    Tag = subtype
                };
                checkBox.Checked += new RoutedEventHandler(checkBoxSubTypes_Checked);
                checkBox.Unchecked += new RoutedEventHandler(checkBoxSubTypes_Unchecked);
                mSubtypes.Add(subtype, checkBox);
                rowStackPanel.Children.Add(checkBox);
            }
            stackPanelSubtypes.Children.Add(mainSubtypeStackPanel);
        }



        private void UpdateStatisticsSectionValues()
        {
            textBoxBAB.Text = mCharacter.BAB.ToString();

            UpdateStats();
            UpdateCMBonuses();

            listBoxFeats.ItemsSource = mCharacter.Feats;
            checkBoxHasAgileManeuvers.IsChecked = mCharacter.HasAgileManeuvers;
            UpdateSkills();
        }

        private void UpdateStats()
        {
            int strength = mCharacter.TotalStats[StatType.Strength];
            int dexterity = mCharacter.TotalStats[StatType.Dexterity];
            int constitution = mCharacter.TotalStats[StatType.Constitution];
            int intelligence = mCharacter.TotalStats[StatType.Intelligence];
            int wisdom = mCharacter.TotalStats[StatType.Wisdom];
            int charisma = mCharacter.TotalStats[StatType.Charisma];

            int baseStrength = mCharacter.BaseStats[StatType.Strength];
            int baseDexterity = mCharacter.BaseStats[StatType.Dexterity];
            int baseConstitution = mCharacter.BaseStats[StatType.Constitution];
            int baseIntelligence = mCharacter.BaseStats[StatType.Intelligence];
            int baseWisdom = mCharacter.BaseStats[StatType.Wisdom];
            int baseCharisma = mCharacter.BaseStats[StatType.Charisma];

            int strengthBonus = (int)Math.Floor(((double)strength - 10) / 2);
            int dexterityBonus = (int)Math.Floor(((double)dexterity - 10) / 2);
            int constitutionBonus = (int)Math.Floor(((double)constitution - 10) / 2);
            int intelligenceBonus = (int)Math.Floor(((double)intelligence - 10) / 2);
            int wisdomBonus = (int)Math.Floor(((double)wisdom - 10) / 2);
            int charismaBonus = (int)Math.Floor(((double)charisma - 10) / 2);

            int baseStrengthBonus = (int)Math.Floor(((double)baseStrength - 10) / 2);
            int baseDexterityBonus = (int)Math.Floor(((double)baseDexterity - 10) / 2);
            int baseConstitutionBonus = (int)Math.Floor(((double)baseConstitution - 10) / 2);
            int baseIntelligenceBonus = (int)Math.Floor(((double)baseIntelligence - 10) / 2);
            int baseWisdomBonus = (int)Math.Floor(((double)baseWisdom - 10) / 2);
            int baseCharismaBonus = (int)Math.Floor(((double)baseCharisma - 10) / 2);

            textBoxSTR.Text = strength.ToString();
            textBoxDEX.Text = dexterity.ToString();
            textBoxCON.Text = constitution.ToString();
            textBoxINT.Text = intelligence.ToString();
            textBoxWIS.Text = wisdom.ToString();
            textBoxCHA.Text = charisma.ToString();

            textBoxBaseSTR.Text = baseStrength.ToString();
            textBoxBaseDEX.Text = baseDexterity.ToString();
            textBoxBaseCON.Text = baseConstitution.ToString();
            textBoxBaseINT.Text = baseIntelligence.ToString();
            textBoxBaseWIS.Text = baseWisdom.ToString();
            textBoxBaseCHA.Text = baseCharisma.ToString();

            textBoxSTRBonus.Text = (strengthBonus >= 0 ? "+" : "") + strengthBonus.ToString();
            textBoxDEXBonus.Text = (dexterityBonus >= 0 ? "+" : "") + dexterityBonus.ToString();
            textBoxCONBonus.Text = (constitutionBonus >= 0 ? "+" : "") + constitutionBonus.ToString();
            textBoxINTBonus.Text = (intelligenceBonus >= 0 ? "+" : "") + intelligenceBonus.ToString();
            textBoxWISBonus.Text = (wisdomBonus >= 0 ? "+" : "") + wisdomBonus.ToString();
            textBoxCHABonus.Text = (charismaBonus >= 0 ? "+" : "") + charismaBonus.ToString();

            textBoxBaseSTRBonus.Text = (baseStrengthBonus >= 0 ? "+" : "") + baseStrengthBonus.ToString();
            textBoxBaseDEXBonus.Text = (baseDexterityBonus >= 0 ? "+" : "") + baseDexterityBonus.ToString();
            textBoxBaseCONBonus.Text = (baseConstitutionBonus >= 0 ? "+" : "") + baseConstitutionBonus.ToString();
            textBoxBaseINTBonus.Text = (baseIntelligenceBonus >= 0 ? "+" : "") + baseIntelligenceBonus.ToString();
            textBoxBaseWISBonus.Text = (baseWisdomBonus >= 0 ? "+" : "") + baseWisdomBonus.ToString();
            textBoxBaseCHABonus.Text = (baseCharismaBonus >= 0 ? "+" : "") + baseCharismaBonus.ToString();
        }

        private void UpdateCMBonuses()
        {
            int strength = mCharacter.TotalStats[StatType.Strength];
            int dexterity = mCharacter.TotalStats[StatType.Dexterity];
            int baseStrength = mCharacter.BaseStats[StatType.Strength];
            int baseDexterity = mCharacter.BaseStats[StatType.Dexterity];
            int strengthBonus = (int)Math.Floor(((double)strength - 10) / 2);
            int dexterityBonus = (int)Math.Floor(((double)dexterity - 10) / 2);
            int baseStrengthBonus = (int)Math.Floor(((double)baseStrength - 10) / 2);
            int baseDexterityBonus = (int)Math.Floor(((double)baseDexterity - 10) / 2);

            int cmbAdd = (mCharacter.HasAgileManeuvers ? dexterityBonus : strengthBonus) + mCharacter.BAB + (-1 * (int)mCharacter.Size);
            int cmdAdd = strengthBonus + dexterityBonus + mCharacter.BAB + (-1 * (int)mCharacter.Size);
            int baseCMBAdd = baseStrengthBonus + mCharacter.BAB + (-1 * (int)mCharacter.Size);
            int baseCMDAdd = baseStrengthBonus + baseDexterityBonus + mCharacter.BAB + (-1 * (int)mCharacter.Size);
            int cmb = cmbAdd + mCharacter.CMB;
            int cmd = 10 + cmdAdd + mCharacter.CMD;
            int baseCMB = baseCMBAdd + mCharacter.CMB;
            int baseCMD = baseCMDAdd + mCharacter.CMD;

            textBoxCMB.Text = mCharacter.CMB.ToString();
            textBoxCMBBonus.Text = (cmbAdd >= 0 ? "+" : "") + cmbAdd;
            textBoxCMBBonusTotal.Text = (cmb >= 0 ? "+" : "") + cmb;

            textBoxNormalCMBBonus.Text = mCharacter.CMB.ToString();
            textBoxBaseCMBBonus.Text = (baseCMBAdd >= 0 ? "+" : "") + baseCMBAdd.ToString();
            textBoxBaseCMBBonusTotal.Text = (baseCMB >= 0 ? "+" : "") + baseCMB.ToString();

            textBoxCMD.Text = mCharacter.CMD.ToString();
            textBoxCMDBonus.Text = "+" + cmdAdd.ToString();
            textBoxCMDBonusTotal.Text = cmd.ToString();

            textBoxNormalCMDBonus.Text = mCharacter.CMD.ToString();
            textBoxBaseCMDBonus.Text = "+" + baseCMDAdd.ToString();
            textBoxBaseCMDBonusTotal.Text = cmd.ToString();
        }

        private void UpdateSkills()
        {
            List<StackPanel> stackPanels = new List<StackPanel>();
            List<Skill> skills = new List<Skill>(mCharacter.Skills);
            skills.Sort(new Comparison<Skill>((theSkill, theOtherSkill) => { return string.Compare(theSkill.Name + theSkill.Subtype, theOtherSkill.Name + theOtherSkill.Subtype); }));
            foreach (Skill skill in skills)
            {
                StackPanel mainStackPanel = new StackPanel()
                {
                    Orientation = Orientation.Horizontal,
                    VerticalAlignment = VerticalAlignment.Center,
                    Tag = skill
                };
                TextBlock textBlock = new TextBlock()
                {
                    Width = 80,
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    Text = skill.Name + (!string.IsNullOrEmpty(skill.Subtype) ? (" (" + skill.Subtype + ")") : ""),
                    VerticalAlignment = VerticalAlignment.Center
                };
                ComboBox statComboBox = new ComboBox()
                {
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    Width = 35,
                    Tag = mainStackPanel,
                    VerticalAlignment = VerticalAlignment.Center
                };

                statComboBox.ItemsSource = Enum.GetValues(typeof(StatType));
                statComboBox.SelectedItem = skill.AlternateStatType ?? skill.BaseStatType;
                int stat = mCharacter.TotalStats[skill.AlternateStatType ?? skill.BaseStatType];
                int statBonus = (int)Math.Floor((double)(stat - 10) / 2);
                TextBlock statTextBlock = new TextBlock()
                {
                    Margin = new Thickness(1),
                    Padding = new Thickness(0),
                    Text = (statBonus >= 0 ? "+" : "") + statBonus.ToString(),
                    Width = 20,
                    VerticalAlignment = VerticalAlignment.Center
                };
                CheckBox classCheckBox = new CheckBox()
                {
                    Content = "Class",
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    IsChecked = skill.IsClassSkill,
                    Tag = mainStackPanel,
                    VerticalAlignment = VerticalAlignment.Center
                };
                TextBox ranksTextBox = new TextBox()
                {
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    Width = 25,
                    BorderThickness = new Thickness(1),
                    Text = skill.Ranks.ToString(),
                    Tag = mainStackPanel
                };
                TextBox miscTextBox = new TextBox()
                {
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    Width = 25,
                    BorderThickness = new Thickness(1),
                    Text = skill.MiscBonus.ToString(),
                    Tag = mainStackPanel
                };
                TextBlock statTextBlockTitle = new TextBlock()
                {
                    Text = "Stat",
                    FontSize = 10,
                    Margin = new Thickness(1),
                    Padding = new Thickness(0)
                };
                TextBlock rankTextBlockTitle = new TextBlock()
                {
                    Text = "Rank",
                    FontSize = 10,
                    Margin = new Thickness(1),
                    Padding = new Thickness(0)
                };
                TextBlock miscTextBlockTitle = new TextBlock()
                {
                    Text = "Misc",
                    FontSize = 10,
                    Margin = new Thickness(1),
                    Padding = new Thickness(0)
                };
                int total = skill.MiscBonus + statBonus + skill.Ranks + ((skill.Ranks > 0 && skill.IsClassSkill) ? 3 : 0);
                TextBlock totalTextBlock = new TextBlock()
                {
                    Text = (total >= 0 ? "+" : "") + total.ToString(),
                    Margin = new Thickness(1),
                    Padding = new Thickness(0),
                    VerticalAlignment = VerticalAlignment.Center
                };

                statComboBox.SelectionChanged += new SelectionChangedEventHandler(statComboBox_SelectionChanged);
                ranksTextBox.TextChanged += new TextChangedEventHandler(ranksTextBox_TextChanged);
                miscTextBox.TextChanged += new TextChangedEventHandler(miscTextBox_TextChanged);

                StackPanel statStackPanel = new StackPanel();
                statStackPanel.Children.Add(statTextBlockTitle);
                statStackPanel.Children.Add(statTextBlock);
                StackPanel rankStackPanel = new StackPanel();
                rankStackPanel.Children.Add(rankTextBlockTitle);
                rankStackPanel.Children.Add(ranksTextBox);
                StackPanel miscStackPanel = new StackPanel();
                miscStackPanel.Children.Add(miscTextBlockTitle);
                miscStackPanel.Children.Add(miscTextBox);

                mainStackPanel.Children.Add(textBlock);
                mainStackPanel.Children.Add(statComboBox);
                mainStackPanel.Children.Add(statStackPanel);
                mainStackPanel.Children.Add(classCheckBox);
                mainStackPanel.Children.Add(rankStackPanel);
                mainStackPanel.Children.Add(miscStackPanel);
                mainStackPanel.Children.Add(totalTextBlock);
                stackPanels.Add(mainStackPanel);
            }
            listBoxSkills.ItemsSource = stackPanels;
        }

        private void UpdateOffenseSectionValues()
        {
            listBoxAttacks.ItemsSource = mCharacter.Attacks;
            textBoxSpace.Text = mCharacter.Space.ToString();
            textBoxReach.Text = mCharacter.Reach.ToString();
            textBoxSpecialAttacks.Text = mCharacter.SpecialAttacks;
            textBoxSpellLikeAbilities.Text = mCharacter.SpellLikeAbilities;
        }

        private void UpdateAttacks()
        {
            listBoxAttacks.ItemsSource = mCharacter.Attacks;
        }

        private int ConvertBonus(int number)
        {
            return (int)Math.Floor((double)(number - 10) / 2);
        }

        private void UpdateDefenseSectionValues()
        {
            UpdateHitDice();
            UpdateSaves();

            textBoxSR.Text = mCharacter.SR >= 0 ? mCharacter.SR.ToString() : "0";
            textBoxDefensivAbilities.Text = mCharacter.DefensiveAbilities;

            UpdateSingleListBoxValues<ImmunityType>(
                new SelectionChangedEventHandler(immuneComboBox_SelectionChanged),
                mCharacter.Immunities,
                listBoxImmunities);
        }

        private void UpdateSaves()
        {
            int baseFortSave = mCharacter.BaseSaves.ContainsKey(SaveType.Fort) ? mCharacter.BaseSaves[SaveType.Fort] : 0;
            int baseWillSave = mCharacter.BaseSaves.ContainsKey(SaveType.Will) ? mCharacter.BaseSaves[SaveType.Will] : 0;
            int baseReflexSave = mCharacter.BaseSaves.ContainsKey(SaveType.Ref) ? mCharacter.BaseSaves[SaveType.Ref] : 0;
            int fortSave = mCharacter.Saves.ContainsKey(SaveType.Fort) ? mCharacter.Saves[SaveType.Fort] : 0;
            int willSave = mCharacter.Saves.ContainsKey(SaveType.Will) ? mCharacter.Saves[SaveType.Will] : 0;
            int reflexSave = mCharacter.Saves.ContainsKey(SaveType.Ref) ? mCharacter.Saves[SaveType.Ref] : 0;
            int baseConBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Constitution] - 10) / 2);
            int baseDexBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Dexterity] - 10) / 2);
            int baseWisBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Wisdom] - 10) / 2);
            int conBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Constitution] - 10) / 2);
            int dexBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Dexterity] - 10) / 2);
            int wisBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Wisdom] - 10) / 2);

            textBoxFort.Text = fortSave.ToString();
            textBoxReflex.Text = reflexSave.ToString();
            textBoxWill.Text = willSave.ToString();
            textBoxBaseFort.Text = baseFortSave.ToString();
            textBoxBaseReflex.Text = baseReflexSave.ToString();
            textBoxBaseWill.Text = baseWillSave.ToString();

            textBoxFortConBonus.Text = (conBonus >= 0 ? "+" : "") + conBonus.ToString();
            textBoxReflexDexBonus.Text = (dexBonus >= 0 ? "+" : "") + dexBonus.ToString();
            textBoxWillWisBonus.Text = (wisBonus >= 0 ? "+" : "") + wisBonus.ToString();
            textBoxBaseFortConBonus.Text = (baseConBonus >= 0 ? "+" : "") + baseConBonus.ToString();
            textBoxBaseReflexDexBonus.Text = (baseDexBonus >= 0 ? "+" : "") + baseDexBonus.ToString();
            textBoxBaseWillWisBonus.Text = (baseWisBonus >= 0 ? "+" : "") + baseWisBonus.ToString();

            int totalFortSave = fortSave + conBonus;
            int totalReflexSave = reflexSave + dexBonus;
            int totalWillSave = willSave + wisBonus;
            int totalBaseFortSave = baseFortSave + baseConBonus;
            int totalBaseReflexSave = baseReflexSave + baseDexBonus;
            int totalBaseWillSave = baseWillSave + baseWisBonus;

            textBoxTotalFort.Text = (totalFortSave >= 0 ? "+" : "") + totalFortSave.ToString();
            textBoxTotalReflex.Text = (totalReflexSave >= 0 ? "+" : "") + totalReflexSave.ToString();
            textBoxTotalWill.Text = (totalWillSave >= 0 ? "+" : "") + totalWillSave.ToString();
            textBoxBaseTotalFort.Text = (totalBaseFortSave >= 0 ? "+" : "") + totalBaseFortSave.ToString();
            textBoxBaseTotalReflex.Text = (totalBaseReflexSave >= 0 ? "+" : "") + totalBaseReflexSave.ToString();
            textBoxBaseTotalWill.Text = (totalBaseWillSave >= 0 ? "+" : "") + totalBaseWillSave.ToString();
        }

        private void UpdateHitDice()
        {
            comboBox6HitDice.SelectedItem = mCharacter.HitDice.ContainsKey(6) ? mCharacter.HitDice[6] : 0;
            comboBox8HitDice.SelectedItem = mCharacter.HitDice.ContainsKey(8) ? mCharacter.HitDice[8] : 0;
            comboBox10HitDice.SelectedItem = mCharacter.HitDice.ContainsKey(10) ? mCharacter.HitDice[10] : 0;
            comboBox12HitDice.SelectedItem = mCharacter.HitDice.ContainsKey(12) ? mCharacter.HitDice[12] : 0;
            textBoxBonusHP.Text = mCharacter.BonusHP.ToString();
            textBlockFinalHPAmount.Text = mCharacter.MaximumHitPoints.ToString();
            textBlockBaseHPAmount.Text = mCharacter.BaseHP.ToString();
        }

        private void UpdateSingleListBoxValues<T>(
            SelectionChangedEventHandler selectionChangedEventHandler,
            IEnumerable<T> itemsToAdd,
            ListBox listBox)
        {
            List<StackPanel> stackPanels = new List<StackPanel>();
            Dictionary<T, ComboBox> comboBoxes = new Dictionary<T, ComboBox>();
            List<T> totalItems = new List<T>(itemsToAdd);
            foreach (T item in itemsToAdd)
            {
                StackPanel stackPanel = new StackPanel() { Orientation = Orientation.Horizontal };
                stackPanel.Tag = item;
                ComboBox comboBox = CreateSwitchComboBox(typeof(T));
                comboBox.Tag = stackPanel;
                comboBox.Width = 150;
                comboBox.Margin = new Thickness(0);
                comboBox.Padding = new Thickness(1);

                TextBlock selectedComboBoxItem = null;
                foreach (TextBlock textBlock in comboBox.Items)
                {
                    if (textBlock.Tag is T)
                    {
                        T itemType = (T)textBlock.Tag;
                        if (totalItems.Contains(itemType) && !itemType.Equals(item))
                        {
                            textBlock.Visibility = Visibility.Collapsed;
                        }
                        else if (itemType.Equals(item))
                        {
                            selectedComboBoxItem = textBlock;
                        }
                    }
                }

                comboBox.SelectedItem = selectedComboBoxItem;
                comboBox.SelectionChanged += new SelectionChangedEventHandler(selectionChangedEventHandler);
                stackPanel.Children.Add(comboBox);
                stackPanels.Add(stackPanel);
            }
            listBox.ItemsSource = stackPanels;
        }

        private void UpdateMainSectionValues()
        {
            textBoxCR.Text = mCharacter.CR;
            comboBoxAlignment.SelectedItem = GetValue(comboBoxAlignment.Items, mCharacter.Alignment);
            comboBoxType.SelectedItem = GetValue(comboBoxType.Items, mCharacter.CreatureType);

            foreach (SubType subtype in mCharacter.SubTypes)
            {
                mSubtypes[subtype].IsChecked = true;
            }
            comboBoxSize.SelectedItem = GetValue(comboBoxSize.Items, mCharacter.Size);

            UpdateInitiative();

            textBoxAura.Text = mCharacter.Aura;
        }

        private void UpdateInitiative()
        {
            textBoxInitiative.Text = mCharacter.InitBonus.ToString();
            double dexBonus = GetStatBonus(mCharacter.TotalStats[StatType.Dexterity]);
            textBoxInitiativeDexBonus.Text = (dexBonus >= 0 ? "+" : string.Empty) + dexBonus.ToString();
            int totalInit = (int)dexBonus + mCharacter.InitBonus;
            textBoxTotalInitiative.Text = (totalInit >= 0 ? "+" : string.Empty) + totalInit.ToString();
        }

        #region Helper

        private double GetStatBonus(int statNumber)
        {
            return Math.Floor(((double)mCharacter.TotalStats[StatType.Dexterity] - 10) / 2);
        }

        private object GetValue(IEnumerable objects, Enum value)
        {
            foreach (TextBlock textBlock in objects)
            {
                if (textBlock.Tag != null && textBlock.Tag.Equals(value))
                {
                    return textBlock;
                }
            }

            return null;
        }

        private IEnumerable<TextBlock> CreateKeys<T>()
        {
            List<T> enums = new List<T>((T[])Enum.GetValues(typeof(T)));
            List<TextBlock> textBlocks = new List<TextBlock>();
            foreach (object theEnum in enums)
            {
                textBlocks.Add(new TextBlock()
                {
                    Text = GetDisplayName(theEnum),
                    Tag = theEnum
                });
            }
            return textBlocks;
        }

        private string GetDisplayName(object theEnum)
        {
            UIDisplayAttribute displayAttribute = ((Enum)theEnum).GetUIDisplayAttribute();
            return displayAttribute != null ? displayAttribute.DisplayName : theEnum.ToString();
        }

        private ComboBox CreateSwitchComboBox(Type enumType)
        {
            List<TextBlock> textBlocks = new List<TextBlock>();
            foreach (Enum theEnum in Enum.GetValues(enumType))
            {
                textBlocks.Add(new TextBlock()
                {
                    Margin = new Thickness(0),
                    Padding = new Thickness(1),
                    Text = GetDisplayName(theEnum),
                    Tag = theEnum
                });
            }

            return new ComboBox() { ItemsSource = textBlocks };
        }

        #endregion

        #endregion

        #region UI Events

        private void immuneComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            ComboBox comboBox = (ComboBox)sender;
            StackPanel stackPanel = (StackPanel)comboBox.Tag;
            ComboBoxItem previousItem = (ComboBoxItem)e.RemovedItems[0];
            ComboBoxItem newItem = (ComboBoxItem)e.AddedItems[0];

            if (previousItem.Content is TextBlock)
            {
                TextBlock textBlock = (TextBlock)previousItem.Content;
                if (textBlock.Tag is ImmunityType)
                {
                    ImmunityType immuneType = (ImmunityType)textBlock.Tag;
                    mCharacter.RemoveImmunity(immuneType);
                }
            }

            if (newItem.Content is TextBlock)
            {
                TextBlock textBlock = (TextBlock)newItem.Content;
                if (textBlock.Tag is ImmunityType)
                {
                    ImmunityType immuneType = (ImmunityType)textBlock.Tag;
                    mCharacter.AddImmunity(immuneType);
                }
            }

            UpdateSingleListBoxValues<ImmunityType>(
                new SelectionChangedEventHandler(immuneComboBox_SelectionChanged),
                mCharacter.Immunities,
                listBoxImmunities);
        }

        private void textBoxCMD_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newCMD = -1;
            if (int.TryParse(textBoxCMD.Text, out newCMD))
            {
                mCharacter.CMD = newCMD;
                UpdateCMBonuses();
            }
        }

        private void textBoxCMB_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newCMB = -1;
            if (int.TryParse(textBoxCMB.Text, out newCMB))
            {
                mCharacter.CMB = newCMB;
                UpdateCMBonuses();
            }
        }

        private void textBoxBAB_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int bab = -1;
            if (int.TryParse(textBoxBAB.Text, out bab))
            {
                mCharacter.BAB = bab;
            }
        }

        private void textBoxBaseCHA_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int cha = -1;
            if (int.TryParse(textBoxBaseCHA.Text, out cha))
            {
                mCharacter.SetBaseStat(StatType.Charisma, cha);
                int bonus = ConvertBonus(cha);
                textBoxBaseCHABonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
            }
        }

        private void textBoxBaseWIS_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int wis = -1;
            if (int.TryParse(textBoxBaseWIS.Text, out wis))
            {
                mCharacter.SetBaseStat(StatType.Wisdom, wis);
                int bonus = ConvertBonus(wis);
                textBoxBaseWISBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateSaves();
            }
        }

        private void textBoxBaseINT_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int INT = -1;
            if (int.TryParse(textBoxBaseINT.Text, out INT))
            {
                mCharacter.SetBaseStat(StatType.Intelligence, INT);
                int bonus = ConvertBonus(INT);
                textBoxBaseINTBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
            }
        }

        private void textBoxBaseCON_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int con = -1;
            if (int.TryParse(textBoxBaseCON.Text, out con))
            {
                mCharacter.SetBaseStat(StatType.Constitution, con);
                int bonus = ConvertBonus(con);
                textBoxBaseCONBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateSaves();
            }
        }

        private void textBoxBaseDEX_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int dex = -1;
            if (int.TryParse(textBoxBaseDEX.Text, out dex))
            {
                mCharacter.SetBaseStat(StatType.Dexterity, dex);
                int bonus = ConvertBonus(dex);
                textBoxBaseDEXBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateSaves();
                UpdateCMBonuses();
                UpdateAttacks();
            }
        }

        private void textBoxBaseSTR_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int str = -1;
            if (int.TryParse(textBoxBaseSTR.Text, out str))
            {
                mCharacter.SetBaseStat(StatType.Strength, str);
                int bonus = ConvertBonus(str);
                textBoxBaseSTRBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateCMBonuses();
                UpdateAttacks();
            }
        }

        private void textBoxCHA_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int cha = -1;
            if (int.TryParse(textBoxCHA.Text, out cha))
            {
                mCharacter.SetTotalStat(StatType.Charisma, cha);
                int bonus = ConvertBonus(cha);
                textBoxCHABonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
            }
        }

        private void textBoxWIS_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int wis = -1;
            if (int.TryParse(textBoxWIS.Text, out wis))
            {
                mCharacter.SetTotalStat(StatType.Wisdom, wis);
                int bonus = ConvertBonus(wis);
                textBoxWISBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateSaves();
            }
        }

        private void textBoxINT_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int INT = -1;
            if (int.TryParse(textBoxINT.Text, out INT))
            {
                mCharacter.SetTotalStat(StatType.Intelligence, INT);
                int bonus = ConvertBonus(INT);
                textBoxINTBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
            }
        }

        private void textBoxCON_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int con = -1;
            if (int.TryParse(textBoxCON.Text, out con))
            {
                mCharacter.SetTotalStat(StatType.Constitution, con);
                int bonus = ConvertBonus(con);
                textBoxCONBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateSaves();
            }
        }

        private void textBoxDEX_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int dex = -1;
            if (int.TryParse(textBoxDEX.Text, out dex))
            {
                mCharacter.SetTotalStat(StatType.Dexterity, dex);
                int bonus = ConvertBonus(dex);
                textBoxDEXBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                mCharacter.SetAC(ACType.Dex, bonus);
                UpdateSkills();
                UpdateSaves();
                UpdateCMBonuses();
                UpdateAttacks();
            }
        }

        private void textBoxSTR_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int str = -1;
            if (int.TryParse(textBoxSTR.Text, out str))
            {
                mCharacter.SetTotalStat(StatType.Strength, str);
                int bonus = ConvertBonus(str);
                textBoxSTRBonus.Text = (bonus >= 0 ? "+" : string.Empty) + bonus.ToString();
                UpdateSkills();
                UpdateCMBonuses();
                UpdateAttacks();
            }
        }

        private void textBoxSpellLikeAbilities_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.SpellLikeAbilities = textBoxSpellLikeAbilities.Text;
        }

        private void textBoxSpecialAttacks_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.SpecialAttacks = textBoxSpecialAttacks.Text;
        }

        private void textBoxReach_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int reach = -1;
            if (int.TryParse(textBoxReach.Text, out reach))
            {
                mCharacter.Reach = reach;
            }
        }

        private void textBoxSpace_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int space = -1;
            if (int.TryParse(textBoxSpace.Text, out space))
            {
                mCharacter.Space = space;
            }
        }

        private void textBoxDefensivAbilities_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.DefensiveAbilities = textBoxDefensivAbilities.Text;
        }

        private void textBoxSR_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newSr = 0;
            if (int.TryParse(textBoxSR.Text, out newSr))
            {
                mCharacter.SR = newSr;
            }
        }

        private void textBoxBaseWill_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxBaseWill.Text, out newWill))
            {
                mCharacter.SetBaseSave(SaveType.Will, newWill);
                int baseWillSave = mCharacter.BaseSaves.ContainsKey(SaveType.Will) ? mCharacter.BaseSaves[SaveType.Will] : 0;
                int baseWisBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Wisdom] - 10) / 2);
                int totalBaseWillSave = baseWillSave + baseWisBonus;
                textBoxBaseTotalWill.Text = (totalBaseWillSave >= 0 ? "+" : "") + totalBaseWillSave.ToString();
            }
        }

        private void textBoxBaseReflex_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxBaseReflex.Text, out newWill))
            {
                mCharacter.SetBaseSave(SaveType.Ref, newWill);
                int baseReflexSave = mCharacter.BaseSaves.ContainsKey(SaveType.Ref) ? mCharacter.BaseSaves[SaveType.Ref] : 0;
                int baseDexBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Dexterity] - 10) / 2);
                int totalBaseReflexSave = baseReflexSave + baseDexBonus;
                textBoxBaseTotalReflex.Text = (totalBaseReflexSave >= 0 ? "+" : "") + totalBaseReflexSave.ToString();
            }
        }

        private void textBoxBaseFort_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxBaseFort.Text, out newWill))
            {
                mCharacter.SetBaseSave(SaveType.Fort, newWill);
                int baseFortSave = mCharacter.BaseSaves.ContainsKey(SaveType.Fort) ? mCharacter.BaseSaves[SaveType.Fort] : 0;
                int baseConBonus = (int)Math.Floor((double)(mCharacter.BaseStats[StatType.Constitution] - 10) / 2);
                int totalBaseFortSave = baseFortSave + baseConBonus;
                textBoxBaseTotalFort.Text = (totalBaseFortSave >= 0 ? "+" : "") + totalBaseFortSave.ToString();
            }
        }

        private void textBoxWill_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxWill.Text, out newWill))
            {
                mCharacter.SetSave(SaveType.Will, newWill);
                int willSave = mCharacter.Saves.ContainsKey(SaveType.Will) ? mCharacter.Saves[SaveType.Will] : 0;
                int wisBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Wisdom] - 10) / 2);
                int totalWillSave = willSave + wisBonus;
                textBoxTotalWill.Text = (totalWillSave >= 0 ? "+" : "") + totalWillSave.ToString();
            }
        }

        private void textBoxReflex_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxReflex.Text, out newWill))
            {
                mCharacter.SetSave(SaveType.Ref, newWill);
                int reflexSave = mCharacter.Saves.ContainsKey(SaveType.Ref) ? mCharacter.Saves[SaveType.Ref] : 0;
                int dexBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Dexterity] - 10) / 2);
                int totalReflexSave = reflexSave + dexBonus;
                textBoxTotalReflex.Text = (totalReflexSave >= 0 ? "+" : "") + totalReflexSave.ToString();
            }
        }

        private void textBoxFort_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newWill = 0;
            if (int.TryParse(textBoxFort.Text, out newWill))
            {
                mCharacter.SetSave(SaveType.Fort, newWill);
                int fortSave = mCharacter.Saves.ContainsKey(SaveType.Fort) ? mCharacter.Saves[SaveType.Fort] : 0;
                int conBonus = (int)Math.Floor((double)(mCharacter.TotalStats[StatType.Constitution] - 10) / 2);
                int totalFortSave = fortSave + conBonus;
                textBoxTotalFort.Text = (totalFortSave >= 0 ? "+" : "") + totalFortSave.ToString();
            }
        }

        private void textBoxBonusHP_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newBonusHp = 0;
            if (int.TryParse(textBoxBonusHP.Text, out newBonusHp))
            {
                mCharacter.BonusHP = newBonusHp;
            }
        }

        private void comboBox12HitDice_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newHitDice = (int)comboBox6HitDice.SelectedItem;
            mCharacter.SetHitDice(12, newHitDice);
        }

        private void comboBox10HitDice_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newHitDice = (int)comboBox10HitDice.SelectedItem;
            mCharacter.SetHitDice(10, newHitDice);
        }

        private void comboBox8HitDice_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newHitDice = (int)comboBox8HitDice.SelectedItem;
            mCharacter.SetHitDice(8, newHitDice);
        }

        private void comboBox6HitDice_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newHitDice = (int)comboBox6HitDice.SelectedItem;
            mCharacter.SetHitDice(6, newHitDice);
        }

        private void comboBoxSize_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            SizeType sizeType = (SizeType)((TextBlock)comboBoxSize.SelectedItem).Tag;
            mCharacter.Size = sizeType;
            mCharacter.SetAC(ACType.Size, (int)sizeType);
        }

        private void comboBoxType_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.CreatureType = (CreatureType)((TextBlock)comboBoxType.SelectedItem).Tag;
        }

        private void checkBoxSubTypes_Unchecked(object sender, RoutedEventArgs e)
        {
            if (mIsRefreshing) return;

            CheckBox checkBoxSender = (CheckBox)sender;
            SubType subType = (SubType)checkBoxSender.Tag;
            mCharacter.RemoveSubType(subType);
        }

        private void checkBoxSubTypes_Checked(object sender, RoutedEventArgs e)
        {
            if (mIsRefreshing) return;

            CheckBox checkBoxSender = (CheckBox)sender;
            SubType subType = (SubType)checkBoxSender.Tag;
            mCharacter.AddSubType(subType);
        }

        private void miscTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int ranks = -1;
            if (sender is TextBox)
            {
                TextBox textBox = (TextBox)sender;
                if (textBox.Tag is StackPanel)
                {
                    StackPanel stackPanel = (StackPanel)textBox.Tag;
                    if (stackPanel.Tag is Skill)
                    {
                        Skill skill = (Skill)stackPanel.Tag;
                        if (int.TryParse(textBox.Text, out ranks))
                        {
                            skill.MiscBonus = ranks;
                            UpdateSkills();
                        }
                    }
                }
            }

        }

        private void ranksTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int ranks = -1;
            if (sender is TextBox)
            {
                TextBox textBox = (TextBox)sender;
                if (textBox.Tag is StackPanel)
                {
                    StackPanel stackPanel = (StackPanel)textBox.Tag;
                    if (stackPanel.Tag is Skill)
                    {
                        Skill skill = (Skill)stackPanel.Tag;
                        if (int.TryParse(textBox.Text, out ranks))
                        {
                            if (ranks >= 0 && ranks <= mCharacter.TotalHitDice)
                            {
                                skill.Ranks = ranks;
                                UpdateSkills();
                            }
                        }
                    }
                }
            }
        }

        private void statComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            if (sender is ComboBox)
            {
                ComboBox comboBox = (ComboBox)sender;
                if (comboBox.Tag is StackPanel)
                {
                    StackPanel stackPanel = (StackPanel)comboBox.Tag;
                    if (stackPanel.Tag is Skill)
                    {
                        Skill skill = (Skill)stackPanel.Tag;
                        if (comboBox.SelectedItem != null && comboBox.SelectedItem is StatType)
                        {
                            StatType statType = (StatType)comboBox.SelectedItem;
                            skill.AlternateStatType = statType;
                            UpdateSkills();
                        }
                    }
                }
            }
        }

        private void textBoxInitiative_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int newInit = -1;
            if (int.TryParse(textBoxInitiative.Text, out newInit))
            {
                textBoxInitiative.Background = Brushes.Transparent;
                mCharacter.InitBonus = newInit;
                mIsRefreshing = true;
                UpdateInitiative();
                mIsRefreshing = false;
            }
            else
            {
                textBoxInitiative.Background = Brushes.LightSalmon;
            }
        }

        private void buttonAddSense_Click(object sender, RoutedEventArgs e)
        {
            SightType newSightType = SightType.Blind;

            foreach (SightType sightType in Enum.GetValues(typeof(SightType)))
            {
                if (!mCharacter.Sight.ContainsKey(sightType))
                {
                    newSightType = sightType;
                    break;
                }
            }

            mPathfinderCharacterView.Add<SightType>(newSightType);
        }

        private void buttonRemoveSense_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxSenses.SelectedItem != null)
            {
                UIEnumView<SightType> sightView = (UIEnumView<SightType>)listBoxSenses.SelectedItem;
                mPathfinderCharacterView.Remove<SightType>(sightView.Value);
            }
        }

        private void textBoxAura_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.Aura = textBoxAura.Text;
        }

        private void buttonAddArmorClass_Click(object sender, RoutedEventArgs e)
        {
            ACType newAcType = ACType.Armor;

            foreach (ACType acType in Enum.GetValues(typeof(ACType)))
            {
                if (!mCharacter.AC.ContainsKey(acType))
                {
                    newAcType = acType;
                    break;
                }
            }

            mPathfinderCharacterView.AddAC(newAcType);
        }

        private void buttonRemoveArmorClass_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxArmorClass.SelectedItem != null)
            {
                ArmorClassView armorClassView = (ArmorClassView)listBoxArmorClass.SelectedItem;
                mPathfinderCharacterView.RemoveAC(armorClassView.ACType);
            }
        }

        private void buttonRecalculate_Click(object sender, RoutedEventArgs e)
        {
            RecalculateHP.ShowRecalculateHPWindow(mCharacter);

            mIsRefreshing = true;
            UpdateHitDice();
            mIsRefreshing = false;
        }

        private void textBlockFinalHPAmount_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int finalHP = 0;
            if (int.TryParse(textBlockFinalHPAmount.Text, out finalHP))
            {
                mCharacter.MaximumHitPoints = finalHP;
            }
        }

        private void textBlockBaseHPAmount_TextChanged(object sender, TextChangedEventArgs e)
        {
            if (mIsRefreshing) return;

            int baseHP = 0;
            if (int.TryParse(textBlockBaseHPAmount.Text, out baseHP))
            {
                mCharacter.BaseHP = baseHP;
            }
        }

        private void buttonAddDamageReduction_Click(object sender, RoutedEventArgs e)
        {
            DRType newDrType = DRType.All;

            foreach (DRType drType in Enum.GetValues(typeof(DRType)))
            {
                if (!mCharacter.DR.ContainsKey(drType))
                {
                    newDrType = drType;
                    break;
                }
            }

            mPathfinderCharacterView.Add<DRType>(newDrType);
        }

        private void buttonRemoveDamageReduction_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxDamageReduction.SelectedItem != null)
            {
                EnumInfoView<DRType> item = (EnumInfoView<DRType>)listBoxEnergyReduction.SelectedItem;
                mPathfinderCharacterView.Remove<DRType>(item.Value);
            }
        }

        private void buttonAddEnergyReduction_Click(object sender, RoutedEventArgs e)
        {
            ERType newErType = ERType.Acid;

            foreach (ERType erType in Enum.GetValues(typeof(ERType)))
            {
                if (!mCharacter.ER.ContainsKey(erType))
                {
                    newErType = erType;
                    break;
                }
            }

            mPathfinderCharacterView.Add<ERType>(newErType);
        }

        private void buttonRemoveEnergyReduction_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxEnergyReduction.SelectedItem != null)
            {
                UIEnumView<ERType> er = (UIEnumView<ERType>)listBoxEnergyReduction.SelectedItem;
                mPathfinderCharacterView.Remove<ERType>(er.Value);
            }
        }

        private void buttonAddImmunities_Click(object sender, RoutedEventArgs e)
        {
            ImmunityType newImmunityType = ImmunityType.Acid;

            foreach (ImmunityType immunityType in Enum.GetValues(typeof(ImmunityType)))
            {
                if (!mCharacter.Immunities.Contains(immunityType))
                {
                    newImmunityType = immunityType;
                    break;
                }
            }

            mCharacter.AddImmunity(newImmunityType);
            mIsRefreshing = true;
            UpdateSingleListBoxValues<ImmunityType>(
                new SelectionChangedEventHandler(immuneComboBox_SelectionChanged),
                mCharacter.Immunities,
                listBoxImmunities);
            mIsRefreshing = false;
        }

        private void buttonRemoveImmunities_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxImmunities.SelectedItem != null)
            {
                StackPanel stackPanel = (StackPanel)listBoxImmunities.SelectedItem;
                ImmunityType immunityType = (ImmunityType)stackPanel.Tag;
                mCharacter.RemoveImmunity(immunityType);

                mIsRefreshing = true;
                UpdateSingleListBoxValues<ImmunityType>(
                    new SelectionChangedEventHandler(immuneComboBox_SelectionChanged),
                    mCharacter.Immunities,
                    listBoxImmunities);
                mIsRefreshing = false;
            }
        }

        private void buttonAddSpeeds_Click(object sender, RoutedEventArgs e)
        {
            SpeedType newSpeedType = SpeedType.Base;

            foreach (SpeedType speedType in Enum.GetValues(typeof(SpeedType)))
            {
                if (!mCharacter.Speed.ContainsKey(speedType))
                {
                    newSpeedType = speedType;
                    break;
                }
            }

            mPathfinderCharacterView.Add<SpeedType>(newSpeedType);
        }

        private void buttonRemoveSpeeds_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxSpeeds.SelectedItem != null)
            {
                UIEnumView<SpeedType> item = (UIEnumView<SpeedType>)listBoxSpeeds.SelectedItem;
                mPathfinderCharacterView.Remove<SpeedType>(item.Value);
            }
        }

        private void buttonAddAttacks_Click(object sender, RoutedEventArgs e)
        {
            EditAttack editAttack = new EditAttack(mCharacter);
            CustomPopup customPopup = new CustomPopup(editAttack);
            customPopup.ShowDialog();
            if (editAttack.Result == true)
            {
                mCharacter.AddAttack(editAttack.Attack);
                listBoxAttacks.ItemsSource = mCharacter.Attacks;
            }
        }

        private void buttonEditAttacks_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxAttacks.SelectedItem != null)
            {
                Attack attack = (Attack)listBoxAttacks.SelectedItem;
                if (mCharacter.Attacks.Contains(attack))
                {
                    EditAttack editAttack = new EditAttack(attack);
                    CustomPopup customPopup = new CustomPopup(editAttack);
                    customPopup.ShowDialog();
                    if (editAttack.Result == true)
                    {
                        mCharacter.RemoveAttack(attack);
                        mCharacter.AddAttack(editAttack.Attack);
                        listBoxAttacks.ItemsSource = mCharacter.Attacks;
                    }
                }
            }
        }

        private void buttonRemoveAttacks_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxAttacks.SelectedItem != null)
            {
                Attack attack = (Attack)listBoxAttacks.SelectedItem;
                if (mCharacter.Attacks.Contains(attack))
                {
                    mCharacter.RemoveAttack(attack);
                    listBoxAttacks.ItemsSource = mCharacter.Attacks;
                }
            }
        }

        private void buttonAddFeats_Click(object sender, RoutedEventArgs e)
        {
            mCharacter.AddFeat(new Feat(string.Empty));
            listBoxFeats.ItemsSource = mCharacter.Feats;
        }

        private void buttonRemoveFeats_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxFeats.SelectedItem != null)
            {
                Feat feat = (Feat)listBoxFeats.SelectedItem;
                if (mCharacter.Feats.Contains(feat))
                {
                    mCharacter.RemoveFeat(feat);
                    listBoxFeats.ItemsSource = mCharacter.Feats;
                }
            }
        }

        private void buttonRemoveSkills_Click(object sender, RoutedEventArgs e)
        {
            if (listBoxSkills.SelectedItem != null)
            {
                StackPanel stackPanel = (StackPanel)listBoxSkills.SelectedItem;
                Skill skill = (Skill)stackPanel.Tag;
                if (!string.IsNullOrEmpty(skill.Subtype))
                {
                    mCharacter.RemoveSkill(skill);
                    UpdateSkills();
                }
            }
        }

        private void checkBoxHasAgileManeuvers_Checked(object sender, RoutedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.HasAgileManeuvers = true;
        }

        private void checkBoxHasAgileManeuvers_Unchecked(object sender, RoutedEventArgs e)
        {
            if (mIsRefreshing) return;

            mCharacter.HasAgileManeuvers = false;
        }

        private void menuItemSubskill_Click(object sender, RoutedEventArgs e)
        {
            MenuItem menuItem = (MenuItem)sender;
            string skillInfo = menuItem.Tag.ToString();
            string skill = skillInfo.Split(',')[0];
            string subskill = skillInfo.Split(',')[1];
            if (!mCharacter.HasSkill(skill, subskill))
            {
                mCharacter.AddSkill(Skill.CreateBaseSkill(skill, subskill));
                UpdateSkills();
            }
        }

        #endregion
    }
}
